package com.asset.dispoal.business.mediation.service.common;

import com.asset.dispoal.business.bsAgreement.domain.db.entity.AgreementInfo;
import com.asset.dispoal.business.bsAgreement.domain.db.mapper.AgreementMapper;
import com.asset.dispoal.business.mediation.domain.db.FormulaData;
import com.asset.dispoal.business.mediation.domain.db.mapper.ReduceOperateMapper;
import com.asset.dispoal.business.mediation.dto.AgreementResponse;
import com.asset.dispoal.business.mediation.dto.ReducePresetResponse;
import com.asset.dispoal.business.mediation.service.converter.MediationConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import tech.mhuang.pacebox.core.date.DateTimeUtil;
import tech.mhuang.pacebox.core.ddd.BaseCommand;
import tech.mhuang.pacebox.core.util.StringUtil;
import tech.mhuang.pacebox.springboot.protocol.Result;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: yf
 * @date: 2022-08-25 11:34:09
 */
@Component
public class QueryAgreementByCaseIdCommand implements BaseCommand<String, Result<ReducePresetResponse>> {
    final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    @Autowired
    private AgreementMapper agreementMapper;
    @Autowired
    private ReduceOperateMapper operateMapper;

    @Override
    public Result<ReducePresetResponse> execute(String caseId) {
        ///合同集合，未处理逾期时间与总额
        List<AgreementInfo> agreementInfos = agreementMapper.queryAgreementInfoByCaseId(caseId);
        penaltyInterestCalculate(agreementInfos);
        for (AgreementInfo agreementInfo : agreementInfos) {
            BigDecimal totalAmount = new BigDecimal(0);
            totalAmount = totalAmount.add(new BigDecimal(agreementInfo.getLawsuitPrincipalAmount()))
                    .add(new BigDecimal(agreementInfo.getLawsuitInterestAmount()))
                    .add(new BigDecimal(agreementInfo.getLitigationFines()));
            agreementInfo.setTotalAmt(totalAmount.toPlainString());
            if (StringUtil.isEmpty(agreementInfo.getOverdueDays())) {
                LocalDate startDate = LocalDate.parse(agreementInfo.getOverdueStartTime(), fmt);
                LocalDate endDate = LocalDate.now();
                agreementInfo.setOverdueDays(String.valueOf(startDate.until(endDate, ChronoUnit.DAYS)));
            }
        }
        ReducePresetResponse presetResponse = new ReducePresetResponse();

        List<AgreementResponse> presetResponses = MediationConverter.INSTANCE.dosToResA(agreementInfos);
        presetResponse.setAgreementList(presetResponses);
        //计算总额
        presetResponse.setTotalNum(presetResponses.size());

        BigDecimal totalAmt = new BigDecimal(0);
        BigDecimal totalLawsuitPrincipalAm = new BigDecimal(0);
        BigDecimal totalLawsuitInterestAmt = new BigDecimal(0);
        BigDecimal totalLitigationFines = new BigDecimal(0);

        for (AgreementResponse presetRespons : presetResponses) {
            totalAmt = totalAmt.add(new BigDecimal(presetRespons.getTotalAmt()));
            totalLawsuitPrincipalAm = totalLawsuitPrincipalAm.add(new BigDecimal(presetRespons.getLawsuitPrincipalAmount()));
            totalLawsuitInterestAmt = totalLawsuitInterestAmt.add(new BigDecimal(presetRespons.getLawsuitInterestAmount()));
            totalLitigationFines = totalLitigationFines.add(new BigDecimal(presetRespons.getLitigationFines()));
        }
        presetResponse.setTotalAmt(totalAmt.toPlainString());
        presetResponse.setTotalLawsuitInterestAmt(totalLawsuitInterestAmt.toPlainString());
        presetResponse.setTotalLitigationFines(totalLitigationFines.toPlainString());
        presetResponse.setTotalLawsuitPrincipalAm(totalLawsuitPrincipalAm.toPlainString());

        return Result.ok(presetResponse);
    }

    /**
     * 1.根据案件id拿到计算公式参数，将公式对应的参数解解析为p1, p2 ,p3, days
     * 2.判断formula_id 是否为空，为空则执行简单公式 p1 * p2 * (当前时间 - 逾期时间)/p3/days
     * formula_id  不为空，则执行动态规则
     *
     * @return
     */
    private void penaltyInterestCalculate(List<AgreementInfo> agreementInfos) {
        String caseId = agreementInfos.get(0).getCaseId();
        List<Map<String, String>> formulaMapList = operateMapper.getFormulaInfoBycaseId(caseId);
        if (null != formulaMapList) {
            for (Map<String, String> formulaMap : formulaMapList) {
                List<String> s = Arrays.asList(formulaMap.get("parameter1"), formulaMap.get("parameter2"), formulaMap.get("parameter3"));
                //参数值映射
                List<Map<String, String>> dataMap = operateMapper.queryParameterMapping(s);
                List<Map<String, Object>> mapList = operateMapper.queryFormularAndBorrower(dataMap, caseId);
                //执行简单公式
                if (!formulaMap.containsKey("formula_id") || formulaMap.get("formula_id") == null) {
                    penaltyInterestCalculate(mapList, agreementInfos);
                    return;
                } else {
                    String formulaId = formulaMap.get("formula_id");
                    List<FormulaData> formulaDataList = operateMapper.queryFormulaDataById(formulaId);
                    if (CollectionUtils.isEmpty(formulaDataList)) {
                        return;
                    }
                    dynamicPenaltyInterestCalculate(mapList, agreementInfos, formulaDataList);
                    return;
                }
            }
        } else {
            for (AgreementInfo agreementInfo : agreementInfos) {
                agreementInfo.setLitigationFines(BigDecimal.ZERO.toPlainString());
            }
        }
    }

    /**
     * 动态规则计算
     *
     * @param mapList
     * @param agreementInfos
     * @param formulaDataList
     */
    private void dynamicPenaltyInterestCalculate(List<Map<String, Object>> mapList, List<AgreementInfo> agreementInfos, List<FormulaData> formulaDataList) {
        for (Map<String, Object> agreementData : mapList) {
            BigDecimal penaltyInterest = BigDecimal.ZERO;
            LocalDate parameter3 = LocalDate.parse(agreementData.get(agreementData.get("parameter3")).toString());
            LocalDate currentDate = LocalDate.parse(agreementData.get("sueDate").toString());
            Long days = DateTimeUtil.getLocalDateDiffDay(parameter3, currentDate);
            if (days >= 0) {
                for (FormulaData formulaData : formulaDataList) {
                    //判断结束时间是否为空  为空改为当前时间
                    if (null == formulaData.getEndTime()) {
                        formulaData.setEndTime(LocalDate.now());
                    }
                    //如果逾期开始时间在公式结束时间后则跳过
                    if (parameter3.isAfter(formulaData.getEndTime())) {
                        continue;
                    }
                    LocalDate beforeTime = formulaData.getStartTime();
                    if (parameter3.isAfter(formulaData.getStartTime())) {
                        beforeTime = parameter3;
                    }
                    LocalDate afterTime = formulaData.getEndTime();
                    if (currentDate.isBefore(formulaData.getEndTime())) {
                        afterTime = currentDate;
                    }
                    BigDecimal parameter1 = (BigDecimal) agreementData.get(agreementData.get("parameter1"));
                    int p4 = (Integer) agreementData.get("parameter4");
                    Long diffDay = DateTimeUtil.getLocalDateDiffDay(beforeTime, afterTime);
                    penaltyInterest = penaltyInterest.add(parameter1.multiply(formulaData.getRate()).multiply(BigDecimal.valueOf(diffDay)).divide(
                            BigDecimal.valueOf(p4), 2, RoundingMode.HALF_UP
                    ));
                }
            }
            for (AgreementInfo agreementInfo : agreementInfos) {
                if (agreementInfo.getAgreementId().equals(agreementData.get("agreementId"))) {
                    agreementInfo.setLitigationFines(penaltyInterest.setScale(2, RoundingMode.HALF_UP).toPlainString());
                }
            }
        }
    }


    /**
     * 简单公式算取罚息
     *
     * @param mapList
     * @param agreementInfos
     */
    private void penaltyInterestCalculate(List<Map<String, Object>> mapList, List<AgreementInfo> agreementInfos) {
        for (Map<String, Object> agreementMap : mapList) {
            //罚息计算 p1 * p2 * (当前时间(sueDate) - 逾期时间(p3)/days(p4)
            BigDecimal p1 = (BigDecimal) agreementMap.get(agreementMap.get("parameter1"));
            BigDecimal p2 = (BigDecimal) agreementMap.get(agreementMap.get("parameter2"));
            LocalDate p3 = LocalDate.parse(agreementMap.get(agreementMap.get("parameter3")).toString());
            LocalDate currentDate = LocalDate.parse(agreementMap.get("sueDate").toString());
            Integer p4 = (Integer) agreementMap.get("parameter4");
            Long diffDay = DateTimeUtil.getLocalDateDiffDay(p3, currentDate);

            BigDecimal result = p1.multiply(p2)
                    .multiply(BigDecimal.valueOf(diffDay))
                    .divide(BigDecimal.valueOf(p4), RoundingMode.HALF_UP);
            for (AgreementInfo agreementInfo : agreementInfos) {
                if (agreementInfo.getAgreementId().equals(agreementMap.get("agreementId"))) {
                    agreementInfo.setLitigationFines(result.toPlainString());
                    agreementInfo.setOverdueDays(String.valueOf(diffDay));
                }
            }
        }
    }
}
